Sites 05 / 13
Layouts
Write your page shell once — head, nav, footer — and let every page drop its content into {{ $slot }}.
Layouts
A layout is the shared shell around your pages — the <html> skeleton, the <head>, your nav and footer. Write it once in resources/views/components/layouts/, and every page slots its content inside. Change the nav in one file, and it changes everywhere. 🧩
A layout is just an ordinary component (see Components) — one that happens to hold the whole document. That's why it lives under components/ and is used with an <x-layouts.…> tag.
The {{ $slot }} variable
A layout is a normal HTML file with one special variable: {{ $slot }}. That's where each page's content lands.
<!-- resources/views/components/layouts/main.blade.php -->
@props(['title' => 'Home', 'description' => ''])
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ $title }}</title>
<meta name="description" content="{{ $description }}">
@vite('resources/css/site.css')
</head>
<body>
<x-nav/>
<main>{{ $slot }}</main>
<x-footer/>
</body>
</html>
Two lines make this a layout: {{ $slot }} (where page content goes) and @vite('resources/css/site.css') (which loads Tailwind and your styles — more below).
Using a layout from a page
Wrap your page content in an <x-layouts.main> tag — the name after x-layouts. is the layout file (without .blade.php):
<!-- resources/views/pages/index.blade.php -->
<x-layouts.main title="Home">
<h1>Welcome!</h1>
</x-layouts.main>
Keep the page inside the tags. Everything the page renders goes between the <x-layouts.main> tags — that's the content that lands in {{ $slot }} and gets the document shell around it.
Layout attributes with @props
The @props([...]) line at the top of the layout declares the attributes it accepts, each with a default. Whatever you pass on the <x-layouts.main> tag becomes a variable inside the layout:
<x-layouts.main title="Pricing" description="Simple plans for every team.">
<!-- inside layouts/main.blade.php -->
<title>{{ $title }}</title>
<meta name="description" content="{{ $description }}">
@props(['title' => 'Home', 'description' => ''])— the props the layout accepts. Anything you don't pass falls back to the default written right there.- Attribute values go in double quotes:
title="Pricing". - Inside the layout, read a prop with
{{ $title }}. Because the default is declared in@props, a page that omitstitlestill renders — it just shows "Home".
Declare before you use. Every variable a layout echoes must be in its @props list (or be the global $site). A stray {{ $subtitle }} that isn't declared is a build error — a fast, visible nudge to add it to @props. When a value is optional, default it: @props(['subtitle' => '']).
Named slots
Sometimes a layout needs more than one content region — say a hero area above the main content. Declare the extra slot in @props and read it like any variable; pages fill it with an <x-slot:name> tag:
<!-- layouts/marketing.blade.php -->
@props(['title' => 'Home', 'hero' => ''])
<!doctype html>
<html lang="en">
<head>
<title>{{ $title }}</title>
@vite('resources/css/site.css')
</head>
<body>
<header class="bg-zinc-900 text-white">{{ $hero }}</header>
<main>{{ $slot }}</main>
</body>
</html>
<!-- a page using it -->
<x-layouts.marketing title="Launch day">
<x-slot:hero>
<h1 class="text-5xl font-bold">We're live!</h1>
</x-slot>
<p>Everything you need, shipping today.</p>
</x-layouts.marketing>
The tag's plain body (everything outside the <x-slot:…> tags) is the default {{ $slot }}; each named slot fills its matching variable.
@vite — Tailwind and your CSS
Put @vite('resources/css/site.css') in your layout's <head>. It loads Tailwind CSS and your resources/css/site.css, so your custom styles apply on every page — in the preview, on your published site, and in exports. No build step to configure, no waiting.
While you're editing, Tailwind compiles right in the browser, so everything works — including arbitrary values like w-[37px] — the moment you type it. When your site is previewed, published or exported, we compile the stylesheet ahead of time instead and ship just the CSS you actually use. That's typically around 7KB rather than the ~70KB compiler, and it means your pages are styled the instant they appear rather than a moment after.
Start your resources/css/site.css with @import "tailwindcss"; and add your own rules below it.
One thing to know about the compiled version: it can only include classes it can see. Write class names out in full — class="bg-red-500" is fine, and so is JavaScript that toggles a complete class name. Building one out of pieces at runtime ('bg-' + color) will look right while you edit and then come up missing on the published site.
Multiple layouts
You can have as many layouts as you like — say, main.blade.php for regular pages and minimal.blade.php for a landing page with no nav. Each page picks its own by name. A page uses one layout at a time.
Switching a page to a different layout works in either mode:
Open the Layout tab in the sidebar and pick a new layout from the Page layout select. The same tab lists the layout's header and footer sections — and on the canvas, + Add to header and + Add to footer pills at the layout's boundaries let you grow the shared shell without leaving the page.
Change the page's wrapper tag to point at a different layout file in components/layouts/:
<!-- resources/views/pages/launch.blade.php -->
<x-layouts.minimal title="Launch day">
<h1>We're live!</h1>
</x-layouts.minimal>
Do I need a layout?
For anything beyond a quick experiment, yes — a layout saves you from repeating your <head>, nav, and footer on every page, and it's where @vite loads your styles. A page can render without one, but then it's on its own for the document shell. Future you says thanks.
Next up
The <x-nav/> and <x-footer/> tags above are Components — the other half of never repeating yourself.